﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;

namespace FieldTools.Util
{
    public static partial class Extention
    {
        private const string Pattern = @"ttp(s)?://([\w-]+\.)+[\w-]+(/[\w-+ ./?%&=]*)?";
        /// <summary>
        /// 是否是url
        /// </summary>
        /// <param name="str_url"></param>
        /// <returns></returns>
        public static bool IsUrl(this string str_url)
        {
            if (str_url.IsNullOrEmpty())
            {
                return false;
            }
            return System.Text.RegularExpressions.Regex.IsMatch(str_url, pattern: Pattern);
        }
        /// <summary>
        /// url是否带有查询参数
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public static bool UrlHaveParam(this string url)
        {
            return url.Contains("?");
        }
        /// <summary>
        /// 移除末尾特定字符
        /// </summary>
        /// <param name="str"></param>
        /// <param name="removeChar"></param>
        /// <returns></returns>
        public static string RemoveEndChar(this string str, char removeChar)
        {
            if (!str.IsNullOrEmpty() && str.EndsWith(removeChar.ToString()))
            {
                return str.Remove(str.Length - 1, 1);
            }
            return str;
        }
        /// <summary>
        /// 移除开头特定字符
        /// </summary>
        /// <param name="str"></param>
        /// <param name="removeChar"></param>
        /// <returns></returns>
        public static string RemoveStartChar(this string str, char removeChar)
        {
            if (!str.IsNullOrEmpty() && str.StartsWith(removeChar.ToString()))
            {
                return str.Remove(0, 1);
            }
            return str;
        }
        /// <summary>
        /// 支付穿连接
        /// </summary>
        /// <param name="str"></param>
        /// <param name="separator"></param>
        /// <param name="otherStr"></param>
        /// <returns></returns>
        public static string Join(this string str, string separator, string otherStr)
        {
            if (str.IsNullOrEmpty())
            {
                return otherStr;
            }
            if (otherStr.IsNullOrEmpty())
            {
                return str;
            }
            return $"{str}{separator}{otherStr}";
        }

        public static string ToUserGroup(this string userId)
            => $"users:{userId}";

        /// <summary>
        /// 转为bool
        /// </summary>
        /// <param name="str">字符串</param>
        /// <returns></returns>
        public static bool ToBool(this string str)
        {
            return bool.Parse(str);
        }
        /// <summary>
        /// bool转整形，0，1
        /// </summary>
        /// <param name="one"></param>
        /// <returns></returns>
        public static int ToInt(this bool one)
        {
            return one ? 1 : 0;
        }
        /// <summary>
        /// 转为字节数组
        /// </summary>
        /// <param name="base64Str">base64字符串</param>
        /// <returns></returns>
        public static byte[] ToBytes_FromBase64Str(this string base64Str)
        {
            return Convert.FromBase64String(base64Str);
        }

        /// <summary>
        /// string转int
        /// </summary>
        /// <param name="str">字符串</param>
        /// <returns></returns>
        public static int ToInt(this string str)
        {
            str = str.Replace("\0", "");
            if (string.IsNullOrEmpty(str))
                return 0;
            return Convert.ToInt32(str);
        }
        public static int? TryToInt(this string str)
        {
            int tmp;
            if (!int.TryParse(str, out tmp))
            {
                return null;
            }
            return tmp;
        }
        public static int TryToInt(this string str, int defaul = 0)
        {
            int tmp;
            if (!int.TryParse(str, out tmp))
            {
                return defaul;
            }
            return tmp;
        }
        /// <summary>
        /// string转long
        /// </summary>
        /// <param name="str">字符串</param>
        /// <returns></returns>
        public static long ToLong(this string str)
        {
            str = str.Replace("\0", "");
            if (string.IsNullOrEmpty(str))
                return 0;

            return Convert.ToInt64(str);
        }

        /// <summary>
        /// 二进制字符串转为Int
        /// </summary>
        /// <param name="str">二进制字符串</param>
        /// <returns></returns>
        public static int ToInt_FromBinString(this string str)
        {
            return Convert.ToInt32(str, 2);
        }

        /// <summary>
        /// 将16进制字符串转为Int
        /// </summary>
        /// <param name="str">数值</param>
        /// <returns></returns>
        public static int ToInt0X(this string str)
        {
            int num = Int32.Parse(str, NumberStyles.HexNumber);
            return num;
        }

        /// <summary>
        /// 转换为double
        /// </summary>
        /// <param name="str">字符串</param>
        /// <returns></returns>
        public static double TryToDouble(this string str)
        {
            if (str.IsNullOrEmpty())
            {
                return 0;
            }
            var val = Convert.ToDouble(str);
            if (double.IsNaN(val))
            {
                return 0;
            }
            return val;
        }
        /// <summary>
        /// 转换为double
        /// </summary>
        /// <param name="str">字符串</param>
        /// <returns></returns>
        public static decimal TryToDecimal(this string str)
        {
            if (str.IsNullOrEmpty())
            {
                return 0;
            }
            decimal decimalV = 0;
            decimal.TryParse(str, out decimalV);
            return decimalV;
            //return Convert.ToDecimal(str);
        }

        /// <summary>
        /// string转byte[]
        /// </summary>
        /// <param name="str">字符串</param>
        /// <returns></returns>
        public static byte[] ToBytes(this string str)
        {
            return Encoding.Default.GetBytes(str);
        }

        /// <summary>
        /// string转byte[]
        /// </summary>
        /// <param name="str">字符串</param>
        /// <param name="theEncoding">需要的编码</param>
        /// <returns></returns>
        public static byte[] ToBytes(this string str, Encoding theEncoding)
        {
            return theEncoding.GetBytes(str);
        }

        /// <summary>
        /// 将16进制字符串转为Byte数组
        /// </summary>
        /// <param name="str">16进制字符串(2个16进制字符表示一个Byte)</param>
        /// <returns></returns>
        public static byte[] To0XBytes(this string str)
        {
            List<byte> resBytes = new List<byte>();
            for (int i = 0; i < str.Length; i = i + 2)
            {
                string numStr = $@"{str[i]}{str[i + 1]}";
                resBytes.Add((byte)numStr.ToInt0X());
            }

            return resBytes.ToArray();
        }

        /// <summary>
        /// 将ASCII码形式的字符串转为对应字节数组
        /// 注：一个字节一个ASCII码字符
        /// </summary>
        /// <param name="str">字符串</param>
        /// <returns></returns>
        public static byte[] ToASCIIBytes(this string str)
        {
            return str.ToList().Select(x => (byte)x).ToArray();
        }

        public static DateTime TryToDateTime(this string str, DateTime defaultVal)
        {
            DateTime date = DateTime.Now;
            if (DateTime.TryParse(str, out date))
            {
                return date;
            }
            return defaultVal;
        }
        public static DateTime? TryToDateTime(this string str)
        {
            DateTime date = DateTime.Now;
            if (DateTime.TryParse(str, out date))
            {
                return date;
            }
            return null;
        }
        /// <summary>
        /// 删除Json字符串中键中的@符号
        /// </summary>
        /// <param name="jsonStr">json字符串</param>
        /// <returns></returns>
        public static string RemoveAt(this string jsonStr)
        {
            Regex reg = new Regex("\"@([^ \"]*)\"\\s*:\\s*\"(([^ \"]+\\s*)*)\"");
            string strPatten = "\"$1\":\"$2\"";
            return reg.Replace(jsonStr, strPatten);
        }

        /// <summary>
        /// 将XML字符串反序列化为对象
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="xmlStr">XML字符串</param>
        /// <returns></returns>
        public static T XmlStrToObject<T>(this string xmlStr)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xmlStr);
            string jsonJsonStr = JsonConvert.SerializeXmlNode(doc);

            return JsonConvert.DeserializeObject<T>(jsonJsonStr);
        }

        /// <summary>
        /// 将XML字符串反序列化为对象
        /// </summary>
        /// <param name="xmlStr">XML字符串</param>
        /// <returns></returns>
        public static JObject XmlStrToJObject(this string xmlStr)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xmlStr);
            string jsonJsonStr = JsonConvert.SerializeXmlNode(doc);

            return JsonConvert.DeserializeObject<JObject>(jsonJsonStr);
        }

        /// <summary>
        /// 将Json字符串转为List'T'
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="jsonStr"></param>
        /// <returns></returns>
        public static List<T> ToList<T>(this string jsonStr)
        {
            return string.IsNullOrEmpty(jsonStr) ? null : JsonConvert.DeserializeObject<List<T>>(jsonStr);
        }

        /// <summary>
        /// 将Json字符串转为DataTable
        /// </summary>
        /// <param name="jsonStr">Json字符串</param>
        /// <returns></returns>
        public static DataTable ToDataTable(this string jsonStr)
        {
            return jsonStr == null ? null : JsonConvert.DeserializeObject<DataTable>(jsonStr);
        }

        /// <summary>
        /// 将Json字符串转为JObject
        /// </summary>
        /// <param name="jsonStr">Json字符串</param>
        /// <returns></returns>
        public static JObject ToJObject(this string jsonStr)
        {
            return jsonStr == null ? JObject.Parse("{}") : JObject.Parse(jsonStr.Replace("&nbsp;", ""));
        }

        /// <summary>
        /// 将Json字符串转为JArray
        /// </summary>
        /// <param name="jsonStr">Json字符串</param>
        /// <returns></returns>
        public static JArray ToJArray(this string jsonStr)
        {
            return jsonStr == null ? JArray.Parse("[]") : JArray.Parse(jsonStr.Replace("&nbsp;", ""));
        }

        /// <summary>
        /// 转为首字母大写
        /// </summary>
        /// <param name="str">字符串</param>
        /// <returns></returns>
        public static string ToFirstUpperStr(this string str)
        {
            return str.Substring(0, 1).ToUpper() + str[1..];
        }

        /// <summary>
        /// 转为首字母小写
        /// </summary>
        /// <param name="str">字符串</param>
        /// <returns></returns>
        public static string ToFirstLowerStr(this string str)
        {
            return str.Substring(0, 1).ToLower() + str[1..];
        }

        /// <summary>
        /// 转为网络终结点IPEndPoint
        /// </summary>=
        /// <param name="str">字符串</param>
        /// <returns></returns>
        public static IPEndPoint ToIPEndPoint(this string str)
        {
            IPEndPoint iPEndPoint = null;
            try
            {
                string[] strArray = str.Split(':').ToArray();
                string addr = strArray[0];
                int port = Convert.ToInt32(strArray[1]);
                iPEndPoint = new IPEndPoint(IPAddress.Parse(addr), port);
            }
            catch
            {
                iPEndPoint = null;
            }

            return iPEndPoint;
        }

        /// <summary>
        /// 将枚举类型的文本转为枚举类型
        /// </summary>
        /// <typeparam name="TEnum">枚举类型</typeparam>
        /// <param name="enumText">枚举文本</param>
        /// <returns></returns>
        public static TEnum ToEnum<TEnum>(this string enumText) where TEnum : struct
        {
            Enum.TryParse(enumText, out TEnum value);

            return value;
        }
        public static TEnum? TryToEnum<TEnum>(this string enumText) where TEnum : struct
        {
            try
            {
                Enum.TryParse(enumText, out TEnum value);
                return value;
            }
            catch (Exception ex)
            {
                return null;
            }

        }
        /// <summary>
        /// 转为MurmurHash
        /// </summary>
        /// <param name="str">字符串</param>
        /// <returns></returns>
        public static uint ToMurmurHash(this string str)
        {
            return MurmurHash2.Hash(Encoding.UTF8.GetBytes(str));
        }

        /// <summary>
        /// 是否为弱密码
        /// 注:密码必须包含数字、小写字母、大写字母和其他符号中的两种并且长度大于8
        /// </summary>
        /// <param name="pwd">密码</param>
        /// <returns></returns>
        public static bool IsWeakPwd(this string pwd)
        {
            if (pwd.IsNullOrEmpty())
                throw new Exception("pwd不能为空");

            string pattern = "(^[0-9]+$)|(^[a-z]+$)|(^[A-Z]+$)|(^.{0,8}$)";
            if (Regex.IsMatch(pwd, pattern))
                return true;
            else
                return false;
        }
        /// <summary>
        /// 是否IP
        /// </summary>
        /// <param name="ip"></param>
        /// <returns></returns>
        public static bool IsIP(this string ip)
        {
            return System.Text.RegularExpressions.Regex.IsMatch(ip, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$");
        }
        /// <summary>
        /// 得到字符串长度，一个汉字长度为2
        /// </summary>
        /// <param name="inputString">参数字符串</param>
        /// <returns></returns>
        public static int StrLength(this string inputString)
        {
            System.Text.ASCIIEncoding ascii = new System.Text.ASCIIEncoding();
            int tempLen = 0;
            byte[] s = ascii.GetBytes(inputString);
            for (int i = 0; i < s.Length; i++)
            {
                if ((int)s[i] == 63)
                    tempLen += 2;
                else
                    tempLen += 1;
            }
            return tempLen;
        }
        /// <summary>
        /// 将以_分割的字符串按照驼峰命名
        /// </summary>
        /// <param name="s"></param>
        /// <param name="toLower"></param>
        /// <returns></returns>
        public static string ToCamelCase(this string s, bool toLower = false)
        {
            var result = new StringBuilder();
            if (s.IsNullOrEmpty())
            {
                return "";
            }
            else if (!s.Contains("_"))
            {
                return s.ConvertFirstChar(toLower);
            }
            // 用下划线将原始字符串分割
            var camels = s.Split('_');
            foreach (var item in camels)
            {
                if (item.IsNullOrEmpty())
                {
                    continue;
                }
                if (result.Length == 0)
                {
                    result.Append(item.ConvertFirstChar(toLower));
                }
                else
                {
                    result.Append(item.ConvertFirstChar(false));
                }
            }
            return result.ToString();
        }
        /// <summary>
        /// 将字符串第一个字母改为大写或者小写
        /// </summary>
        /// <param name="s"></param>
        /// <param name="toLower"></param>
        /// <returns></returns>
        public static string ConvertFirstChar(this string s, bool toLower)
        {
            var temp = toLower ? s.Substring(0, 1).ToLower() : s.Substring(0, 1).ToUpper();
            return $"{temp}{s[1..]}";
        }
        /// <summary>
        /// 将传入的字符串中间部分字符替换成特殊字符
        /// </summary>
        /// <param name="value">需要替换的字符串</param>
        /// <param name="startLen">前保留长度</param>
        /// <param name="endLen">尾保留长度</param>
        /// <param name="replaceChar">特殊字符</param>
        /// <returns>被特殊字符替换的字符串</returns>
        public static string ReplaceWithSpecialChar(this string value, int startLen = 4, int endLen = 4, int charLen = 4, char specialChar = '*')
        {
            try
            {
                int lenth = value.Length - startLen - endLen;
                if (lenth < 0)
                {
                    return value;
                }
                string replaceStr = value.Substring(startLen, lenth);

                string specialStr = string.Empty;
                var replaceLen = replaceStr.Length;
                if (replaceLen > charLen)
                {
                    replaceLen = charLen;
                }
                for (int i = 0; i < replaceLen; i++)
                {
                    specialStr += specialChar;
                }
                return $"{value.Substring(0, startLen)}{specialStr}{value.Substring(startLen + lenth, endLen)}";
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 判断是不是UTF8编码
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static bool IsUTF8(this string str)
        {
            bool bln = true;
            char[] chars = str.ToCharArray();
            foreach (char cr in chars)
            {
                int ichar = (int)cr;
                if (ichar > 127 && ichar <= 255)
                {
                    bln = false;
                    break;
                }
            }
            return bln;
        }
        /// <summary>
        /// 获取网络资源文件后缀
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public static string GetNetResourcesSuffix(this string url)
        {
            if (url.IsUrl())
            {
                var sp = url.Split(".");
                if (sp != null && sp.Length > 1)
                {
                    if (sp.Last().Length > 4)
                    {
                        //部分会以结尾的标记区分，比如微信公众号
                        var sp2 = sp.Last().Split('=');
                        if (sp2 != null && sp2.Length > 1)
                        {
                            return sp2.Last();
                        }
                    }
                    return sp.Last();
                }
                return string.Empty;
            }
            else
            {
                return string.Empty;
            }
        }
        /// <summary>
        /// 网络资源是否是图片
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public static bool IsNetResourcesPic(this string url)
        {
            var suffix = GetNetResourcesSuffix(url);
            if (string.IsNullOrEmpty(suffix)) return false;
            List<string> picSuffixs = new() { "jpg", "jpeg", "bmp", "wbmp", "webp", "tiff", "png", "gif", "svg", "ico" };
            if (picSuffixs.Contains(suffix.ToLower())) return true;
            return false;
        }
        /// <summary>
        /// 保存到文件，纯文本格式
        /// </summary>
        /// <param name="str"></param>
        /// <param name="filePath"></param>
        public static void SaveToFile(this string str, string filePath)
        {
            if(string.IsNullOrEmpty(str) || string.IsNullOrEmpty(filePath)) return;
            filePath = filePath.Replace("/","\\");
            var path = filePath.Replace(filePath.Split('\\').Last(),"");
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
                if (!File.Exists(filePath))
                {
                    using FileStream fs = File.Create(filePath);
                    fs.Close();
                }
                using FileStream file = File.OpenWrite(filePath);
                var bs = str.ToBytes();
                file.Write(bs);
                file.Close();
            }
        }
    }
}
